package com.youtills.core.email;

import javax.mail.Address;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: ravi
 * Date: 8/11/12
 * Time: 12:56 PM
 * To change this template use File | Settings | File Templates.
 */
public class EmailMessage implements IEmailMessage{

    /** The Empty String. */
    private static final String EMPTY_STRING = "";

    /** List of attachments these are file paths. */
    private List<File> attachments = new ArrayList<File>();

    /** BCC addresses list */
    private List<Address> bcc = new ArrayList<Address>();

    /** Body content, initialized as empty string. */
    private String body = EMPTY_STRING;

    /** CC Addresses List */
    private List<Address> cc = new ArrayList<Address>();

    /** From addresses List */
    private List<Address> from = new ArrayList<Address>();

    /** Mail type is html or not */
    private boolean isHtml = false;

    /** To Addresses list */
    private List<Address> replyTo = new ArrayList<Address>();


    /** Subject initialized as empty string to avoid null pointer exception if no subject is set. */
    private String subject = EMPTY_STRING;

    /** To Addresses list */
    private List<Address> to = new ArrayList<Address>();

    /**
     * The email address to return in case of bounces.
     *
     * If this is not set, the default "From" address will be used.
     */
    private String returnPath = null;

    /**
     * Creates a new EmailMessage object.
     *
     * @param   toAddress  to address
     *
     * @throws  EmailException  if address has problems.
     */
    public EmailMessage(String toAddress) throws EmailException {

        try {
            this.to.add(new InternetAddress(toAddress));
        } catch (AddressException e) {
            throw new EmailException(e);
        }
    }

    /**
     * Creates a new EmailMessage object.
     */
    public EmailMessage() {
        super();
    }

    /**
     * Adds attachment.
     *
     * @param   fileName  filename.
     *
     * @throws  java.io.FileNotFoundException  if file doesn't exist.
     */
    public void addAttachment(String fileName) throws FileNotFoundException {
        File file = new File(fileName);

        if (file.isFile()) {
            addAttachment(file);
        } else {
            throw new FileNotFoundException(fileName + " Not Found");
        }
    }

    /**
     * adds attachment.
     *
     * @param  file  java.io.File object.
     */
    public void addAttachment(File file) {
        this.attachments.add(file);
    }

    /**
     * Adds all files as attachments.
     *
     * @param  files  list of java.io.File objects
     *
     * @since  2/28/07
     */
    public void addAttachments(List<File> files) {
        this.attachments.addAll(files);
    }

    /**
     * attachments. List of files
     *
     * @return  list of files
     */
    public List<File> getAttachments() {
        return attachments;
    }

    /**
     * Gives you an array of Bcc addresses.
     *
     * @return  array of bcc addresses
     */
    public Address[] getBccArray() {
        return getArray(bcc);
    }

    /**
     * Returns an unmodifiable list of bcc addresses.
     *
     * @return  List of addresses
     */
    public List<Address> getBcc() {
        return Collections.unmodifiableList(bcc);
    }

    /**
     * gives you mail body/content.
     *
     * @return  mail content
     */
    public String getBody() {
        return body;
    }

    /**
     * Gives you an array of cc addresses.
     *
     * @return  cc addresses array
     */
    public Address[] getCcArray() {
        return getArray(cc);
    }

    /**
     * Returns an unmodifiable list of cc addresses.
     *
     * @return  List of addresses.
     */
    public List<Address> getCc() {
        return Collections.unmodifiableList(cc);
    }

    /**
     * Gives you an array of from addresses.
     *
     * @return  array of from addresses
     */
    public Address[] getFromArray() {
        return getArray(from);
    }

    /**
     * Returns an unmodifiable list of from addresses.
     *
     * @return  List of addresses.
     */
    public List<Address> getFrom() {
        return Collections.unmodifiableList(from);
    }


    /**
     * Gives you an array of reply to addresses
     *
     * @return  array of replyTo addresses
     */
    public Address[] getReplyToArray() {
        return getArray(replyTo);
    }

    /**
     * Returns an unmodifiable list of replyto addresses.
     *
     * @return  list of addresses.
     */
    public List<Address> getReplyTo() {
        return Collections.unmodifiableList(replyTo);
    }

    /**
     * Gets mail subject
     *
     * @return  mail subject
     */
    public String getSubject() {
        return subject;
    }

    /**
     * Gives you an array of To addresses.
     *
     * @return  to addresses
     */
    public Address[] getToArray() {
        return getArray(to);
    }

    /**
     * Returns an unmodifiable list of to addresses.
     *
     * @return  List of addresses.
     */
    public List<Address> getTo() {
        return Collections.unmodifiableList(to);
    }

    /**
     * Tells you whether the mail is an HTML mail or not.
     *
     * @return  boolean
     */
    public boolean isHtml() {
        return isHtml;
    }

    /**
     * Cleans existing attachements and adds given attachements.
     *
     * @param  attachments  List of file objects to be added as attachements.
     */
    public void setAttachments(List<File> attachments) {
        this.attachments.clear();
        addAttachments(attachments);
    }

    /**
     * Cleans existing list of BCC address and new one to the list.
     *
     * @param  bcc  List of addresses.
     */
    public void setBcc(List<Address> bcc) {
        this.bcc.clear();
        addBcc(bcc);
    }

    /**
     * Adds bcc addresses to the list of bcc addresses.
     *
     * @param  bcc  list of address to be added to bcc list.
     *
     * @since  2/28/07
     */
    public void addBcc(List<Address> bcc) {
        this.bcc.addAll(bcc);
    }

    /**
     * Clears existing list and adds given address to list.
     *
     * @param  bcc  javax.mail.Address
     */
    public void setBcc(Address bcc) {
        this.bcc.clear();
        addBcc(bcc);
    }

    /**
     * Adds bcc address to the list.
     *
     * @param  bcc  javax.mail.Address
     *
     * @since  2/28/07
     */
    public void addBcc(Address bcc) {
        this.bcc.add(bcc);
    }

    /**
     * adds bcc address to the list.
     *
     * @param   bcc  address
     *
     * @throws  EmailException  for invalid address.
     *
     * @since   2/28/07
     */
    public void addBcc(String bcc) throws EmailException {

        try {
            addBcc(new InternetAddress(bcc));
        } catch (AddressException e) {
            throw new EmailException("Invalid bcc address: " + bcc);
        }
    }

    /**
     * Clears existing list and adds new one to the list.
     *
     * @param   bcc  javax.mail.Address
     *
     * @throws  EmailException  will be thrown for invalid address.
     */
    public void setBcc(String bcc) throws EmailException {

        try {
            setBcc(new InternetAddress(bcc));
        } catch (AddressException e) {
            throw new EmailException(e.toString(), e);
        }
    }

    /**
     * Sets email body text
     *
     * @param  body  String
     */
    public void setBody(String body) {
        this.body = body;
    }

    /**
     * Cleans existing list of cc address and adds all addresses from given list.
     *
     * @param  cc  DOCUMENT ME!
     */
    public void setCc(List<Address> cc) {
        this.cc.clear();
        addCc(cc);
    }

    /**
     * Adds given list of addresses to the cc list.
     *
     * @param  cc  list of addresses
     *
     * @since  2/28/07
     */
    public void addCc(List<Address> cc) {
        this.cc.addAll(cc);
    }


    /**
     * Clears existing list and adds given address to the list.
     *
     * @param  cc  javax.mail.Address
     */
    public void setCc(Address cc) {
        this.cc.clear();
        addCc(cc);
    }



    /**
     * Clears existing list of cc addresses and adds given address to the list.
     *
     * @param   cc  address as String
     *
     * @throws  EmailException  for invalid addresses.
     */
    public void setCc(String cc) throws EmailException {

        try {
            setCc(new InternetAddress(cc));
        } catch (AddressException e) {
            throw new EmailException("Invalid CC address.", e);
        }
    }

    /**
     * Clears existing list of addresses and adds given list of addresses.
     *
     * @param  from  List of from addresses.
     */
    public void setFrom(List<Address> from) {
        this.from.clear();
        addFrom(from);
    }

    /**
     * Adds list of from addresses.
     *
     * @param  from  list of addresses.
     *
     * @since  2/28/07
     */
    public void addFrom(List<Address> from) {
        this.from.addAll(from);
    }

    /**
     * Clears exisitng list and adds given address to the list.
     *
     * @param  from  from address.
     */
    public void setFrom(Address from) {
        this.from.clear();
        addFrom(from);
    }

    /**
     * Adds given from address the from address list.
     *
     * @param  from  javax.mail.Address
     *
     * @since  2/28/07
     */
    public void addFrom(Address from) {
        this.from.add(from);
    }

    /**
     * Adds from address to the list.
     *
     * @param   from  address
     *
     * @throws  EmailException  for invalid address
     *
     * @since   2/28/07
     */
    public void addFrom(String from) throws EmailException {

        try {
            addFrom(new InternetAddress(from));
        } catch (AddressException e) {
            throw new EmailException("Invalid from address: " + from);
        }
    }

    /**
     * Clears existing list and adds given one to the list.
     *
     * @param   from  address as String
     *
     * @throws  EmailException  for invalid address
     */
    public void setFrom(String from) throws EmailException {

        try {
            setFrom(new InternetAddress(from));
        } catch (AddressException e) {
            throw new EmailException(e.toString(), e);
        }
    }

    /**
     * Sets html flag
     *
     * @param  html  boolean
     */
    public void setHtml(boolean html) {
        isHtml = html;
    }

    /**
     * Sets mail subject.
     *
     * @param  subject  String
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * Clears existing To addresses list and adds given list.
     *
     * @param  to  list of to addresses.
     */
    public void setTo(List<Address> to) {
        this.to.clear();
        addTo(to);
    }

    /**
     * Clears existing To addresses list and adds given one to the list.
     *
     * @param  to  javax.mail.Address
     */
    public void setTo(Address to) {
        this.to.clear();
        addTo(to);
    }

    /**
     * Adds to addresses to the list
     *
     * @param  to  list of addresses.
     *
     * @since  2/28/07
     */
    public void addTo(List<Address> to) {
        this.to.addAll(to);
    }


    /**
     * Clears existing list of addresses and adds given one to the list.
     *
     * @param   to  address as String
     *
     * @throws  EmailException  for invalid address
     */
    public void setTo(String to) throws EmailException {

        try {
            setTo(new InternetAddress(to));
        } catch (AddressException e) {
            throw new EmailException(e.toString(), e);
        }
    }

    /**
     * Adds address to the list.
     *
     * @param  to  javax.mail.Address
     *
     * @since  2/26/07
     */
    public void addTo(Address to) {
        this.to.add(to);
    }


    /**
     * Adds given address to the cc addresses list.
     *
     * @param  cc  javax.mail.Address
     *
     * @since  2/26/07
     */
    public void addCc(Address cc) {
        this.cc.add(cc);
    }

    /**
     * Adds cc address to the list.
     *
     * @param   cc  address
     *
     * @since   2/28/07
     *
     * @throws  EmailException  for invalid address.
     */
    public void addCc(String cc) throws EmailException {

        try {
            addCc(new InternetAddress(cc));
        } catch (AddressException e) {
            throw new EmailException("Invalid cc address: " + cc);
        }
    }

    /**
     * adds address to the list.
     *
     * @param   to  String
     *
     * @throws  EmailException  for invalid address
     *
     * @since   2/26/07
     */
    public void addTo(String to) throws EmailException {

        try {
            addTo(new InternetAddress(to));
        } catch (AddressException e) {
            throw new EmailException(e.toString(), e);
        }
    }


    /**
     * Cleans existing list of reply to address and adds all addresses from given list.
     *
     * @param  replyTo  DOCUMENT ME!
     */
    public void setReplyTo(List<Address> replyTo) {
        this.replyTo.clear();
        addReplyTo(replyTo);
    }

    /**
     * Adds given list of addresses to the replyTo list.
     *
     * @param  replyTo  list of addresses
     *
     * @since  2/28/07
     */
    public void addReplyTo(List<Address> replyTo) {
        this.replyTo.addAll(replyTo);
    }


    /**
     * Clears existing list and adds given address to the list.
     *
     * @param  replyTo  javax.mail.Address
     */
    public void setReplyTo(Address replyTo) {
        this.replyTo.clear();
        addReplyTo(replyTo);
    }


    /**
     * Adds given address to the replyTo addresses list.
     *
     * @param  replyTo  javax.mail.Address
     *
     * @since  2/26/07
     */
    public void addReplyTo(Address replyTo) {
        this.replyTo.add(replyTo);
    }


      /**
     * adds address replyTo the list.
     *
     * @param   replyTo  String
     *
     * @throws  EmailException  for invalid address
     *
     * @since   2/26/07
     */
    public void addReplyTo(String replyTo) throws EmailException {

        try {
            addReplyTo(new InternetAddress(replyTo));
        } catch (AddressException e) {
            throw new EmailException(e.toString(), e);
        }
    }


    /**
     * Clears existing list of ReplyTo addresses and adds given address to the list.
     *
     * @param   replyTo  address as String
     *
     * @throws  EmailException  for invalid addresses.
     */
    public void setReplyTo(String replyTo) throws EmailException {

        try {
            setReplyTo(new InternetAddress(replyTo));
        } catch (AddressException e) {
            throw new EmailException("Invalid ReplyTo address.", e);
        }
    }

    /**
     * Get the return path address that will be used in the MAIL FROM.
     *
	 * @return the returnPath
	 */
	public String getReturnPath() {
		return returnPath;
	}

	/**
	 * Set the email address to use as the MAIL FROM.
	 *
	 * If this is not set, the default "From" address will be used.
	 *
	 * @param returnPath the returnPath to set
	 */
	public void setReturnPath(String returnPath) {
		this.returnPath = returnPath;
	}

	/**
     * Generates an array from list.
     *
     * @param   list  - addresses
     *
     * @return  array of Addresses
     */
    private static Address[] getArray(final List<Address> list) {
        Address[] addresses = new Address[list.size()];

        for (int i = 0; i < list.size(); i++) {
            addresses[i] = list.get(i);
        }

        return addresses;
    }
}